package com.mattgarner.jaddas.dataset;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import com.mattgarner.jaddas.node.data.LocalTableDataProvider;
import com.mattgarner.jaddas.node.data.TableHeader;
import com.mattgarner.jaddas.util.MRUCache;

public class DataSet {

	private int dsID;
	private String dsName;
	private String dsDescription = "";
	
	private TableHeader dataHeader;
	
	private int dsSerialNumber = 0;
	
	private int partitionMaxTupleCount = 1024;
	private int nextPartitionID = 0;
	
	
	private HashMap<Integer, DataSetPartition> dsPartitions;
	private ArrayList<Integer> dsLocalPartitions;
	private ArrayList<Integer> dsRemotePartitions;	
	
	private int openPartitionID;
	private int openMirrorPartitionID;
	
	public DataSet(byte[] serializedData) {
		initialize();
		initializeFromByteArray(serializedData);
	}
	
	public DataSet(int ID, String name, String description, TableHeader dataTableHeader) {
		this.dsID = ID;
		this.dsName = name;
		this.dsDescription = description;
		this.dataHeader = dataTableHeader;
		
		initialize();
	}
	
	public DataSet() {
		// dummy
	}
	
	private final void initialize() {
		dsPartitions = new HashMap<Integer, DataSetPartition>();
		dsLocalPartitions = new ArrayList<Integer>();
		dsRemotePartitions = new ArrayList<Integer>();
	}
	
	// getters
	public final int getID() {
		return dsID;
	}
	
	public final int getSerialNumber() {
		return dsSerialNumber;
	}
	
	public final String getName() {
		return dsName;
	}
	
	public final String getDescription() {
		return dsDescription;
	}
	
	public final TableHeader getDataTableHeader() {
		return dataHeader;
	}
	
	public final String getDataName() {
		return dsID + "-" + dsName;
	}
	
	public final int getNextPartitionID() {
		dsSerialNumber++;
		return nextPartitionID++;
	}
	
	public final int getCurrentPartitionID() {
		return nextPartitionID;
	}
	
	public final int getPartitionMaxTupleCount() {
		return partitionMaxTupleCount;
	}
	
	public final int getOpenPartitionID() {
		return openPartitionID;
	}
	
	public final int getOpenMirrorPartitionID() {
		return openMirrorPartitionID;
	}
	
	//
	
	public final void setOpenPartitionID(final int partitionID) {
		this.openPartitionID = partitionID;
	}
	
	public final void setOpenMirrorPartitionID(final int partitionID) {
		this.openMirrorPartitionID = partitionID;
	}
	
	
	public final void registerPartition(final DataSetPartition dsPartition) {
		dsPartitions.put(dsPartition.getPartitionID(), dsPartition);
		if(dsPartition.isLocal()) {
			dsLocalPartitions.add(dsPartition.getPartitionID());
		} else {
			dsRemotePartitions.add(dsPartition.getPartitionID());
		}
	}
	
	public final DataSetPartition getDataSetPartitionByID(final int dsID) {
		return dsPartitions.get(dsID);
	}
	
	/// serialization
	public final byte[] serializeToByteArray() {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream stream = new DataOutputStream(baos);
		
		if(dsDescription == null) {
			dsDescription = "" + '\000';
		}
		
		try {
			stream.writeInt(dsID);
			stream.writeInt(dsSerialNumber);
			stream.writeUTF(dsName);
			stream.writeUTF(dsDescription);
			stream.writeInt(partitionMaxTupleCount);
			stream.writeInt(nextPartitionID);
			byte[] dataHeaderBytes = dataHeader.serializeToByteArray();
			stream.writeInt(dataHeaderBytes.length);
			stream.write(dataHeaderBytes);
			stream.close();
			baos.close();
			return baos.toByteArray();
		} catch (IOException e) {
			return null;
		}
	}
	
	public final void initializeFromByteArray(byte[] dsBytes) {
		ByteArrayInputStream bais = new ByteArrayInputStream(dsBytes);
		DataInputStream stream = new DataInputStream(bais);
		
		try {
			dsID = stream.readInt();
			dsSerialNumber = stream.readInt();
			dsName = stream.readUTF();
			dsDescription = stream.readUTF();
			partitionMaxTupleCount = stream.readInt();
			nextPartitionID = stream.readInt();
			
			int dHdrBytesLength = stream.readInt();			
			byte[] dHdrBytes = new byte[dHdrBytesLength];
			stream.read(dHdrBytes, 0, dHdrBytesLength);
			dataHeader = new TableHeader(dHdrBytes);

			stream.close();
			bais.close();
		} catch(IOException e) {
			return;
		}
	}
	
	
}
